#ifndef _L_IRREGULAR_TABLE_120130_H
#define _L_IRREGULAR_TABLE_120130_H

#include <ltypes.h>
#include <lmacros.h>

#include <vector>

#include <boost/assert.hpp>
#include <boost/noncopyable.hpp>

LLIB_BEGIN
namespace util {

/* The table declaration */
template <typename T> class IrregularTable;

/* The rows class of irregular table */
template <typename T>
class IrregularTableRow {
public:
    /* Override operator [] */
    inline T& operator [] (Int32 index) {
        BOOST_ASSERT(index >= 0 && index < _sz);
        return _ptr[index];
    }

    /* Override const operator [] */
    const inline T& operator [] (Int32 index) const {
        BOOST_ASSERT(index >= 0 && index < _sz);
        return _ptr[index];
    }

    /* Get the row length */
    inline Int32 size() const { return _sz; }

private:
    /* The row start pointer */
    T*      _ptr;

    /* The length of row */
    Int32   _sz;

    /* We hide the constructor */
    IrregularTableRow(T* ptr, Int32 size) : _ptr(ptr), _sz(size) {}

    friend IrregularTable<T>;
};


/* Irregular table is a efficient class for two-dimensional array
 * with irregular row length.
 */
template <typename T>
class IrregularTable : public boost::noncopyable {
public:
    /* The row type */
    typedef IrregularTableRow<T> Row;

    /* The constructor. Need to define size for each row */
    IrregularTable(std::vector<Int32>& row_size) {
        _rowNum = SZ(row_size);
        _rowOffset = new Int32[_rowNum+1];
        _rowOffset[0] = 0;
        FOR(I,0,_rowNum) _rowOffset[I+1] = _rowOffset[I] + row_size[I];
        Int32 total = _rowOffset[_rowNum];
        BOOST_ASSERT(total > 0 || _rowNum == 0);
        if(total > 0)
            _data = new T[ total ];
        else
            _data = NULL;
    }

    /* The destructor */
    ~IrregularTable() {
        delete[] _rowOffset;
        delete[] _data;
    }

    /* Override operator [] */
    inline Row operator [] (Int32 index) {
        BOOST_ASSERT(index >= 0 && index < _rowNum);
        return Row(_data + _rowOffset[index], _rowOffset[index+1] - _rowOffset[index]);
    }

    /* Get the table length (row number) */
    inline Int32 size() const { return _rowNum; }

    /* Get row size config */
    std::vector<Int32> GetRowSize() const {
        std::vector<Int32> res(_rowNum);
        FOR(I,0,_rowNum) res[I] = _rowOffset[I+1] - _rowOffset[I];
        return res;
    }

private:
    /* Table row number */
    Int32   _rowNum;

    /* Offset index for each row */
    Int32*  _rowOffset;

    /* Datas in line */
    T*      _data;

};

} // end of namespace util
LLIB_END

#endif
